# -*- coding:utf-8 -*-
import json
import re
import time
import os
import random
import sys
import textwrap

import requests

# @Time    : 2023/8/31 13:54
# @Author  : zengwenjia
# @Email   : zengwenjia@lingxi.ai
# @File    : sales.py
# @Software: LLM_internal

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
from bot.bot import Bot
from loguru import logger
import asyncio

from bot.insurance_sales_huize.agent.user_intention import UserIntentionExtract

from common import constants
from bot.insurance_sales_huize.agent.user_questioning import QuestioningDisputeResolution
from bot.insurance_sales_huize.agent.conversation_agent import Conversation
from bot.insurance_sales_huize.knowledge_expand import csv_read as knowledge_expand
from bot.insurance_sales_gpt.demo.cache_dict import cache_dict
from bot.insurance_sales_huize.knowledge_question_solution.knowledge_embedding import BGEQuery
from bot.insurance_sales_huize.knowledge_question_solution import csv_read
import tiktoken

logger.add("./log/短险执行日志_{time}.log", retention="1 days")
record_maps = csv_read.read_map()
data_map = record_maps[0]
label_map = record_maps[1]

data_map_expand = knowledge_expand.read_map()

class Sales(Bot):
    """销售机器人"""

    knowledge_question_solution_query = BGEQuery()
    knowledge_question_solution_query.load_knowledge_base()

    def __init__(self):
        self.user_info = ''
        self.solution = ""
        self.max_token_length = 1024 * 2
        self.role_name = "慧择保险网的电话销售顾问"
        self.business_background = """保险公司:慧择网-销售健康类保险和财富类保险"""
        self.model_name = "self"
        self.user_job = ''
        self.process_knowledge = ''
        self.multi_knowledge = ''
        self.user_question = ''
        self.skill = ''
        self.sop = ''
        self.content = ''
        self.underwriting = ''
        self.count_token = 0
        self.max_agent_token = 0
        self.user_intention = ""
        self.skill_knowledge = ""

    def get_token_count(self, input_str, res_str):
        env = tiktoken.encoding_for_model('gpt-4')
        return len(env.encode(input_str + res_str))

    def format_conversation_history(self, conversation_context, max_token_length=None):
        dialogue_history = ""
        if (not max_token_length) or (max_token_length > self.max_token_length):
            max_token_length = self.max_token_length
        # 倒序遍历record_list
        for record in conversation_context[::-1]:
            next_dialogue_history = dialogue_history
            if record['role'] == constants.ROLE_USER:
                next_dialogue_history = "用户:" + record["content"] + "\n" + dialogue_history
            elif record['role'] == constants.ROLE_ASSISTANT:
                next_dialogue_history = self.role_name + ":" + record["content"] + "\n" + dialogue_history
            if len(next_dialogue_history) > max_token_length:
                break
            else:
                dialogue_history = next_dialogue_history
        return dialogue_history

    async def get_user_question(self):
        try:
            questioning_dispute_resolution = QuestioningDisputeResolution(self.role_name, self.conversation_history_str,
                                                                          self.user_base_info)
            self.user_question = await questioning_dispute_resolution.achat_auto_llm(type=self.model_name)
            token_size = self.get_token_count(questioning_dispute_resolution.prompt, self.user_question)
            self.count_token = self.count_token + token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            logger.info(
                f"session_id:{self.session_id},content:{self.content},agent-用户疑义是:{self.user_question},本次消耗token:{token_size}")
            if self.user_question not in ('用户无问题', '用户无问题。'):
                # 查询用户疑问知识库
                knowledges = self.knowledge_question_solution_query.search_with_score(self.user_question, top_k=2,
                                                                                         limit_score=1.1)
                if knowledges:
                    self.solution = "\n".join(knowledge.metadata.get('text') for knowledge in knowledges)
                else:
                    self.solution = ""
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.user_question = ""


    async def get_user_intention(self):
        # 用户意向的agent
        try:
            user_intention_extract = UserIntentionExtract(self.role_name, self.conversation_history_str)
            self.user_intention = await user_intention_extract.achat_auto_llm(type=self.model_name)
            logger.info(f"session_id:{self.session_id}, 用户意向是:{self.user_intention}")
            cache_dict["user_intention"] = self.user_intention
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.user_intention = ""

    async def generate_reply(self):
        """
        查询用户疑问解答话术 以及当前节点销售流程话术,以及用户意向， 并生成最终话术
        """
        try:
            conversation = Conversation(self.role_name,
                                        self.business_background,
                                        self.conversation_history_str, self.user_question, self.solution,
                                        self.sop,
                                        self.skill,
                                        self.user_job,
                                        self.underwriting,
                                        self.user_intention)
            result = await conversation.achat_auto_llm(type=self.model_name)
            token_size = self.get_token_count(conversation.prompt, result)
            self.count_token = self.count_token + token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            logger.info(
                f"session_id:{self.session_id},content:{self.content},agent-话术生成是:{result},本次消耗token是:{token_size}")
            logger.info(
                f"session_id:{self.session_id},本轮对话单个agent消耗最大的token数为{self.max_agent_token},所有agent总共消耗token:{self.count_token}")
            return result
        except Exception as e:
            logger.exception(e)
            return "出错了，我不知道怎么回答你的问题，你可以换个问法试试"

    async def async_reply_web(self, context, session_id, content='', name='',user_base_info='',is_need_format=1):
        start_time = time.time()
        if is_need_format:
            conversation = self.format_conversation_history(context)
        else:
            conversation=context
        # logger.info("conversation is " + str(conversation) + " session_id is " + str(session_id))
        self.session_id = session_id
        self.context = context
        self.conversation_history_str = conversation
        self.user_base_info = user_base_info
        self.content = content
        if f'cache_user_info:{session_id}' in cache_dict:
            self.user_info = cache_dict[f'cache_user_info:{session_id}']
        if len(self.context) > 1:
            # 用户疑义(solution)\意向判断(user_intention)
            user_question_task = asyncio.create_task(self.get_user_question())
            user_intention_task = asyncio.create_task(self.get_user_intention())
            await asyncio.gather(user_question_task, user_intention_task)
            result_number = await self.generate_reply()
        else:  #skill 是销售流程的话术
            self.background_knowledge = ""
            self.skill = ""
            self.solution = ""
            self.user_intention = ""
            result_number = "ZC12-1C"
        result_number=result_number.strip()
        logger.warning(
            f"原始返回的录音编号:{result_number}")
        result_number_ = re.findall('([A-Za-z0-9-|/]+)', result_number)
        if result_number_ is None or len(result_number_) == 0:
            logger.error('没有识别到录音编号,模型返回值:{result_number}', result_number=result_number)
            return '没有找到录音编号'
        # result_number = result_number_[0]
        number_arr = result_number.split('|')
        result_ = ""
        label_ = ""
        for number in number_arr:
            number.strip()
            temp_result = data_map.get(number)
            if temp_result is not None:
                result_ += temp_result
            temp_label = label_map.get(number)
            if temp_label is not None:
                if len(label_) == 0:
                    label_ = temp_label
                else:
                    label_ += "|" + temp_label

            if "?" in result_ or "？" in result_ or '再见' in result_ or '您不要挂电话，马上为您服务' in result_:
                break
        if result_ is None:
            result_ = result_number
        execution_time = time.time() - start_time
        if label_ is not None and len(label_) > 0:
            result_ += "-" + label_
        logger.warning(
            f"session_id:{self.session_id}，执行时间:{execution_time}，录音编号:{result_number},动作标签:{label_}, 最终生成话术是:{result_}")
        cache_dict[f'cache_user_info:{session_id}'] = self.user_info
        logger.info(f"---------------分割线--------------")
        return result_

    async def async_reply(self, context, session_id, user_base_info='') -> dict:
        # 最终返回给dm的数据
        dm_result = {}
        start_time = time.time()
        conversation = self.format_conversation_history(context)
        conversation.replace('@@quiet@@', '(用户没说话)')
        conversation = re.sub('(\[.*?\])|(\[#.*?#\])', '', conversation)
        self.session_id = session_id
        self.context = context
        self.conversation_history_str = conversation
        self.user_base_info = user_base_info
        if f'cache_user_info:{session_id}' in cache_dict:
            self.user_info = cache_dict[f'cache_user_info:{session_id}']
        if len(self.context) < 2:
            result_number = "TY02-3C"
        elif self.context[-1] == '(用户没说话)':
            result_number = random.choice(['TY439-1C', 'TY440-1C'])
        else:
            # 用户疑义\销售流程
            user_question_task = asyncio.create_task(self.get_user_question())
            sales_sop_task = asyncio.create_task(self.get_sales_sop())
            await asyncio.gather(user_question_task, sales_sop_task)
            result_number = await self.generate_reply()
        result_number_ = re.findall('([A-Za-z0-9-|/]+)', result_number)
        if result_number_ is None or len(result_number_) == 0:
            logger.error('没有识别到录音编号,模型返回值:{result_number}', result_number=result_number)
            return {'reply_text': '没有找到录音编号', 'voice_record': '', 'label': ''}
        # result_number = result_number_[0]
        dm_number =""
        dm_label = []
        number_arr = result_number.split('|')
        result_ = ""
        for number in number_arr:
            number = number.strip()
            temp_result = data_map.get(number)
            # 查找可替换的录音编号
            if number in data_map_expand:
                number_random = random.choice(data_map_expand.get(number))
                if number is not None:
                    number = number_random['录音编号']
                    logger.info(f"session_id:{self.session_id},录音编号变更 {number_random['原录音编号']} TO {number_random['录音编号']} ,话术变更 {temp_result['话术']} TO {number_random['话术']}")
            dm_number = dm_number+","+number
            if temp_result is not None:
                result_ += temp_result['话术']
            if '动作标签' in temp_result:
                dm_label.append(temp_result['动作标签'])
            if "?" in result_ or "？" in result_ or '挂机' in dm_label or '转人' in dm_label:
                break
        if result_ is None:
            result_ = result_number
        execution_time = time.time() - start_time
        logger.warning(f"session_id:{self.session_id}，执行时间:{execution_time}，录音编号:{result_number},最终生成话术是:{result_}")
        logger.info(f"---------------分割线--------------")
        dm_result["reply_text"] = result_
        dm_result["voice_record"] = dm_number
        dm_number["label"] = ','.join(dm_label)
        return dm_result



def send_message_to_wechat_group(content):
    webhook_url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=46a11f7d-4bdc-4092-a04c-9118f7b3d412'
    headers = {'Content-Type': 'application/json'}
    data = {
        "msgtype": "markdown",
        "markdown": {
            "content": content,
        }
    }
    dumps = json.dumps(data, ensure_ascii=False).replace('<br>', r'\n\n')
    response = requests.post(
        url=webhook_url,
        headers=headers,
        data=dumps.encode('utf-8')
    )


class SaleGPT:
    def reply(self, query, session_id=None, user_base_info=None):
        if session_id not in cache_dict:
            cache_dict[session_id] = []
        conversation_history = cache_dict.get(session_id)
        if len(conversation_history) > 0:
            conversation_dict = {}
            conversation_dict["role"] = "user"
            conversation_dict["content"] = query
            cache_dict[session_id].append(conversation_dict)

        sales = Sales()
        if user_base_info:
            sales.user_base_info = user_base_info
        result = asyncio.run(sales.async_reply_web(conversation_history, session_id, content=query))
        conversation_dict = {}
        conversation_dict["role"] = "assistant"
        conversation_dict["content"] = result
        cache_dict[session_id].append(conversation_dict)
        return result


def format_conversation_history(conversation_context):
    dialogue_history = []
    for record in conversation_context:
        if record['role'] == constants.ROLE_USER:
            dialogue_history.append('<font color="warning">用户:' + record["content"] + '</font>')
        elif record['role'] == constants.ROLE_ASSISTANT:
            dialogue_history.append('<font color="info">保险销售员:' + record["content"] + '</font>')
    return '<br>'.join(dialogue_history)


if __name__ == '__main__':
    conversation_history = []
    user_input = ''
    while True:
        sales = Sales()
        result = asyncio.run(sales.async_reply_web(conversation_history, "123", content=user_input))
        conversation_dict = {}
        conversation_dict["role"] = "assistant"
        conversation_dict["content"] = result
        conversation_history.append(conversation_dict)
        logger.info('历史对话缓存:{}'.format(conversation_history))
        if '再见' in result or '马上为您服务' in result:
            logger.info("*******对话已经结束：转人/挂机*******\n\n\n")
            conversation_history = []
            user_input = ''
        else:
            user_input = input("请输入用户的对话：")
            conversation_dict = {}
            conversation_dict["role"] = "user"
            conversation_dict["content"] = user_input
            conversation_history.append(conversation_dict)
